package com.hqd.ch03.v47.core.annotation;

import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.util.Collection;
import java.util.function.Predicate;
import java.util.stream.Stream;

public interface MergedAnnotations extends Iterable<MergedAnnotation<Annotation>> {

    /**
     * 创建集合注解，默认查找策略DIRECT
     *
     * @param element
     * @return
     */
    static MergedAnnotations from(AnnotatedElement element) {
        return from(element, SearchStrategy.DIRECT);
    }

    static MergedAnnotations from(AnnotatedElement element, SearchStrategy searchStrategy) {
        return from(element, searchStrategy, RepeatableContainers.standardRepeatables());
    }

    static MergedAnnotations from(AnnotatedElement element, SearchStrategy searchStrategy,
                                  RepeatableContainers repeatableContainers) {

        return from(element, searchStrategy, repeatableContainers, AnnotationFilter.PLAIN);
    }

    static MergedAnnotations from(AnnotatedElement element, SearchStrategy searchStrategy,
                                  RepeatableContainers repeatableContainers, AnnotationFilter annotationFilter) {

        return TypeMappedAnnotations.from(element, searchStrategy, repeatableContainers, annotationFilter);
    }

    /**
     * 创建集合策略
     *
     * @param annotations
     * @return
     */
    static MergedAnnotations from(Annotation... annotations) {
        return from(annotations, annotations);
    }

    static MergedAnnotations from(Object source, Annotation... annotations) {
        return from(source, annotations, RepeatableContainers.standardRepeatables());
    }

    /**
     * 创建组合注解集合
     *
     * @param source
     * @param annotations
     * @param repeatableContainers
     * @return
     */
    static MergedAnnotations from(Object source, Annotation[] annotations, RepeatableContainers repeatableContainers) {
        return from(source, annotations, repeatableContainers, AnnotationFilter.PLAIN);
    }

    static MergedAnnotations from(Object source, Annotation[] annotations,
                                  RepeatableContainers repeatableContainers, AnnotationFilter annotationFilter) {

        return TypeMappedAnnotations.from(source, annotations, repeatableContainers, annotationFilter);
    }

    static MergedAnnotations of(Collection<MergedAnnotation<?>> annotations) {
        return MergedAnnotationsCollection.of(annotations);
    }

    <A extends Annotation> boolean isPresent(Class<A> annotationType);

    boolean isPresent(String annotationType);

    <A extends Annotation> boolean isDirectlyPresent(Class<A> annotationType);

    boolean isDirectlyPresent(String annotationType);

    /**
     * 获取对应注解
     *
     * @param annotationType
     * @param <A>
     * @return
     */
    <A extends Annotation> MergedAnnotation<A> get(Class<A> annotationType);

    <A extends Annotation> MergedAnnotation<A> get(Class<A> annotationType,
                                                   Predicate<? super MergedAnnotation<A>> predicate);

    <A extends Annotation> MergedAnnotation<A> get(Class<A> annotationType,
                                                   Predicate<? super MergedAnnotation<A>> predicate,
                                                   MergedAnnotationSelector<A> selector);

    <A extends Annotation> MergedAnnotation<A> get(String annotationType);

    <A extends Annotation> MergedAnnotation<A> get(String annotationType,
                                                   Predicate<? super MergedAnnotation<A>> predicate);

    <A extends Annotation> MergedAnnotation<A> get(String annotationType,
                                                   Predicate<? super MergedAnnotation<A>> predicate,
                                                   MergedAnnotationSelector<A> selector);

    <A extends Annotation> Stream<MergedAnnotation<A>> stream(Class<A> annotationType);

    <A extends Annotation> Stream<MergedAnnotation<A>> stream(String annotationType);

    Stream<MergedAnnotation<Annotation>> stream();


    /**
     * 注解查找策略
     */
    enum SearchStrategy {
        /**
         * 不考虑继承关系，只获取当前类上的注解
         */
        DIRECT,
        /**
         * 继承关系只考虑@Inherited
         */
        INHERITED_ANNOTATIONS,
        /**
         * 查找直接声明的注解以及超类声明的注解。这与 INHERITED_ANNOTATIONS 类似
         * 但不依赖 @Inherited 注解
         */
        SUPERCLASS,
        /**
         * 在整个类型层次结构中进行完整搜索，包括超类和实现的接口
         */
        TYPE_HIERARCHY,
        /**
         * 在整个类型层次结构中进行搜索，包括超类、接口以及任何封闭类
         */
        TYPE_HIERARCHY_AND_ENCLOSING_CLASSES
    }

}

